C# 自定义特性Attribute与反射调用

您所在的位置:网站首页 unity 反射调用方法 C# 自定义特性Attribute与反射调用

C# 自定义特性Attribute与反射调用

2023-09-23 12:57| 来源: 网络整理| 查看: 265

C# 自定义特性Attribute与反射调用 前言1.AttributeUtil.cs2.两个打印任务类(1)PrintTaskA.cs(2)PrintTaskB.cs 3.Program.cs

前言 👨‍💻👨‍🌾📝记录学习成果,以便温故而知新

  一个项目有对个打印任务,每个打印任务调用不同的Excel模板进行打印。利用自定义特性PrintTaskAttribute来标识打印任务函数,再利用反射的方法把打印任务名与打印方法的映射关系存到字典里。以下是把项目中的思路抽出来整了个演示项目。

项目结构如下: 项目结构

1.AttributeUtil.cs

文件中含AttributeUtil(特性工具类)、PrintTaskAttribute(打印任务特性)与ObjectMethodInfo(特性内容与映射方法类)。AttributeUtil工具类有MapPrintTaskToMethod与InvokePrintTask两个方法,MapPrintTaskToMethod方法映射程序集中所有含打印任务特性的方法,InvokePrintTask调用映射的打印任务方法。

namespace Print { /// /// 特性工具类 /// author: Antonio /// class AttributeUtil { /// /// 打印任务映射处理方法 /// author: Antonio /// /// 打印任务与调用方法映射字典 /// 程序集 public void MapPrintTaskToMethod(out Dictionary objectMethodDictionary, string assemblyName) { objectMethodDictionary = new Dictionary(); Assembly assembly = Assembly.Load(assemblyName); Type[] types = assembly.GetTypes(); foreach (Type t in types) { object _Object = null; //Debug.WriteLine(t.FullName, "类名"); MethodInfo[] methodInfos = t.GetMethods(); foreach (MethodInfo methodInfo in methodInfos) { //Debug.WriteLine(methodInfo.Name, "方法名"); IEnumerable attributes = methodInfo.GetCustomAttributes(); foreach (Attribute attr in attributes) { //Debug.WriteLine(attr.ToString(), "特性"); if (attr is PrintTaskAttribute) { PrintTaskAttribute printTaskAttribute = (PrintTaskAttribute)attr; string printTaskName = printTaskAttribute.printTaskName; //Debug.WriteLine(printTaskName, "PrintTaskName"); if (!objectMethodDictionary.ContainsKey(printTaskName)) { ObjectMethodInfo objectMethod = new ObjectMethodInfo(); if (_Object == null) { _Object = Activator.CreateInstance(t); } objectMethod._Object = _Object;//类 objectMethod._MethodInfo = methodInfo;//方法 objectMethodDictionary[printTaskName] = objectMethod; } else { Debug.Fail(t.FullName + "." + methodInfo.Name + "[" + printTaskAttribute.TypeId + "(PrintTaskName)]:" + printTaskName + "已存在"); } } } } } } /// /// 调用打印任务 /// author: Antonio /// /// 打印任务与调用方法映射字典 /// 打印任务 /// 参数 /// public bool InvokePrintTask(Dictionary objectMethodDictionary, string printTaskName, Dictionary dic) { bool b = false; if (objectMethodDictionary.ContainsKey(printTaskName)) { object o = objectMethodDictionary[printTaskName]._MethodInfo.Invoke(objectMethodDictionary[printTaskName]._Object, new object[] { dic }); b = (bool)o; } return b; } } /// /// 打印任务特性 /// author: Antonio /// [AttributeUsage(AttributeTargets.Method)] public class PrintTaskAttribute : Attribute { public string printTaskName { get; set; } public PrintTaskAttribute(string printTaskName) { this.printTaskName = printTaskName; } } /// /// 特性内容与映射方法类 /// author: Antonio /// public class ObjectMethodInfo { /// /// 类 /// public object _Object { get; set; } /// /// 类方法 /// public MethodInfo _MethodInfo { get; set; } } }

核心代码:

object o = objectMethodDictionary[printTaskName]._MethodInfo.Invoke(objectMethodDictionary[printTaskName]._Object, new object[] { dic });

objectMethodDictionary[printTaskName]._MethodInfo是调用的方法。 参数objectMethodDictionary[printTaskName]._Object是方法所属对象。 new object[] { dic }是传参。

2.两个打印任务类 (1)PrintTaskA.cs

模拟打印任务A下有个模板

namespace Print { /// /// 打印任务A /// author: Antonio /// class PrintTaskA { /// /// 任务A-模板1 /// author: Antonio /// /// 参数 /// [PrintTask("任务A-模板1")] public bool Task_A_1(Dictionary dic) { Console.WriteLine("===任务A-模板1==="); Console.WriteLine("姓名:" + dic["name"]); Console.WriteLine("年龄" + dic["age"]); return true; } /// /// 任务A-模板2 /// author: Antonio /// /// 参数 /// [PrintTask("任务A-模板2")] public bool Task_A_2(Dictionary dic) { Console.WriteLine("===任务A-模板2==="); Console.Write("姓名:" + dic["name"]); Console.Write(" "); Console.WriteLine("年龄" + dic["age"]); return true; } } } (2)PrintTaskB.cs

模拟打印任务B下有3个模板

namespace Print { /// /// 打印任务B /// author: Antonio /// class PrintTaskB { /// /// 任务B-模板1 /// author: Antonio /// /// 参数 /// [PrintTask("任务B-模板1")] public bool Task_B_1(Dictionary dic) { Console.WriteLine("===任务B-模板1==="); Console.WriteLine(dic["Tom"] + "和" +dic["Jerry"] + "一起工作"); return true; } /// /// 任务B-模板2 /// author: Antonio /// /// 参数 /// [PrintTask("任务B-模板2")] public bool Task_B_2(Dictionary dic) { Console.WriteLine("===任务B-模板1==="); Console.WriteLine(dic["Tom"] + "帮助" + dic["Jerry"] ); return true; } /// /// 任务B-模板3 /// author: Antonio /// /// 参数 /// [PrintTask("任务B-模板3")] public bool Task_B_3(Dictionary dic) { Console.WriteLine("===任务B-模板1==="); Console.WriteLine(dic["Jerry"] + "帮助" + dic["Tom"]); return true; } } } 3.Program.cs

演示效果代码如下:

namespace Print { class Program { static void Main(string[] args) { Dictionary objectMethodDictionary = new Dictionary(); AttributeUtil util = new AttributeUtil(); //程序集Print中打印任务映射处理方法 util.MapPrintTaskToMethod(out objectMethodDictionary, "Print"); Dictionary dic1 = new Dictionary(); dic1["name"] = "Tom"; dic1["age"] = 18; util.InvokePrintTask(objectMethodDictionary, "任务A-模板1", dic1);//调用任务A-模板1 util.InvokePrintTask(objectMethodDictionary, "任务A-模板2", dic1);//调用任务A-模板3 Dictionary dic2 = new Dictionary(); dic2["Tom"] = "Tom"; dic2["Jerry"] = "Jerry"; util.InvokePrintTask(objectMethodDictionary, "任务B-模板1", dic2);//调用任务B-模板1 util.InvokePrintTask(objectMethodDictionary, "任务B-模板2", dic2);//调用任务B-模板2 util.InvokePrintTask(objectMethodDictionary, "任务B-模板3", dic2);//调用任务B-模板3 Console.Read(); } } }

运行效果 在实际项目中调用打印任务,打印任务名一般是以动态参数形式传入,dic参数应与打印任务匹配,这样的话如果有新的打印任务,只需新增打印任务功能方法,其它代码可以少改,甚至不需改动。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3